#include "ftp_server.h"

char recv_buff[BUF_SIZE]; // 用来存放接收的消息
char send_buff[BUF_SIZE]; // 用来存放发送的消息

int FILE_SIZE;
char *file_buf;

bool ftplisten_to_client(void)
{
    int sock_fd, client_fd;
    // 创建套接字
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd < 0)
    {
        perror("socket()");
        return false;
    }

    // 填充服务器地址信息
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;                // 指定通信协议
    servaddr.sin_port = htons(PORT);              // 指定端口号
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 本主机的任意ip

    // 绑定
    int ret;
    ret = bind(sock_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    if (ret < 0)
    {
        perror("bind()");
        return false;
    }

    // 监听
    ret = listen(sock_fd, LISTEN_NUM);
    if (ret < 0)
    {
        perror("listen()");
        return false;
    }

    // 从请求连接的队列中取出一个请求
    struct sockaddr_in clientaddr;
    int len = sizeof(clientaddr);
    client_fd = accept(sock_fd, (struct sockaddr *)&clientaddr, &len);
    if (client_fd < 0)
    {
        perror("accept()");
        return false;
    }
    printf("客户ip: %s, 端口号：%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));


    get_cmd(client_fd);


    // 进行消息处理
    while (processMsg(&client_fd))
    {
        // sleep(2);
    }
}

bool processMsg(int *clientfd)
{
    memset(recv_buff, 0, sizeof(recv_buff));
    int n_size = recv(*clientfd, (char *)recv_buff, 1024, 0);
    if (n_size <= 0)
    {
        printf("客户端断开连接...\n");
        return false;
    }
    // printf("接收：%s\n", recv_buff);
    // 将接收到的消息强制转换为MSG_HEAD
    MSG_HEAD *mes = (MSG_HEAD *)recv_buff;
    printf("file = %s\n", mes->un.FILE_INFO.filename);

    // 判断接收到的消息类型并处理
    switch (mes->msg_ID)
    {
    case MSG_FILE_NAME:
        // 文件名，此时我们需要得到这个文件的大小
        // 再把文件名发送给客户端
        readfile(clientfd, mes);
        break;
    case MSG_SEND:
        // 服务器发送文件
        printf("MSG_SEND\n");
        serv_send_file(*clientfd, mes);
        break;
    case MSG_SUCCESSED:
        printf("MSG_SUCCESSED\n");
        // 文件传输成功处理
        success_to_client(*clientfd);
        return false;
        break;
    default:
        break;
    }
    return true;
}

bool readfile(int *clientfd, MSG_HEAD *pmsghead)
{
    // 打开文件
    FILE *fp = fopen(pmsghead->un.FILE_INFO.filename, "rb");
    if (fp == NULL)
    {
        printf("文件 \"%s\" 不存在\n", pmsghead->un.FILE_INFO.filename);

        // 告诉客户端文件找不到
        MSG_HEAD msg = {.msg_ID = MSG_OPEN_FAILED};
        int ret = send(*clientfd, (char *)&msg, sizeof(msg), 0);
        if (ret <= 0)
        {
            printf("客户端 send() 失败\n");
            // return false;
        }
        return false;
    }

    // 文件存在
    fseek(fp, 0, SEEK_END); // 先将文件指针从头移到尾
    FILE_SIZE = ftell(fp);  // 再记录当前文件指针的位置，这就是文件大小
    fseek(fp, 0, SEEK_SET); // 再将文件指针恢复到文件开头的位置

    char temp[100] = {0};
    char text[100] = {0};
    char drive[128];
    char dir[128];
    _splitpath(pmsghead->un.FILE_INFO.filename, drive, dir, temp, text);

    MSG_HEAD filenamemsg;
    memset(&filenamemsg, 0, sizeof(filenamemsg));
    filenamemsg.msg_ID = MSG_FILE_SIZE;
    // struct MSGHeader fileNameMsg ;
    // fileNameMsg.msgID = MSGFILESIZE;
    strcat(temp, text);
    strcpy(filenamemsg.un.FILE_INFO.filename, temp);
    filenamemsg.un.FILE_INFO.file_size = FILE_SIZE;
    // printf("size = %ld\n", sizeof(filenamemsg));
    // printf("filename = %s       size = %d\n",filenamemsg.FILE_INFO.filename, filenamemsg.FILE_INFO.file_size);
    int ret = send(*clientfd, (char *)&filenamemsg, sizeof(filenamemsg), 0);
    if (ret <= 0)
    {
        printf("send() error\n");
        return false;
    }

    // 读取文件内容
    file_buf = (char *)calloc(FILE_SIZE + 1, sizeof(char));
    if (file_buf == NULL)
    {
        printf("动态内存分配失败\n");
        return false;
    }

    fread(file_buf, sizeof(char), FILE_SIZE, fp);

    // serv_send_file(clientfd, )

    fclose(fp);
    return true;
}

void _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext)
{
    char *p_whole_name;

    drive[0] = '\0';
    if (NULL == path)
    {
        dir[0] = '\0';
        fname[0] = '\0';
        ext[0] = '\0';
        return;
    }

    if ('/' == path[strlen(path)])
    {
        strcpy(dir, path);
        fname[0] = '\0';
        ext[0] = '\0';
        return;
    }

    p_whole_name = rindex(path, '/');
    if (NULL != p_whole_name)
    {
        p_whole_name++;
        _split_whole_name(p_whole_name, fname, ext);

        snprintf(dir, p_whole_name - path, "%s", path);
    }
    else
    {
        _split_whole_name(path, fname, ext);
        dir[0] = '\0';
    }
}

static void _split_whole_name(const char *whole_name, char *fname, char *ext)
{
    char *p_ext;

    p_ext = rindex(whole_name, '.');
    if (NULL != p_ext)
    {
        strcpy(ext, p_ext);
        snprintf(fname, p_ext - whole_name + 1, "%s", whole_name);
    }
    else
    {
        ext[0] = '\0';
        strcpy(fname, whole_name);
    }
}

bool serv_send_file(int clientfd, MSG_HEAD *pmsg)
{
    // int ret = send(clientfd, file_buf, FILE_SIZE, 0);
    // 如果文件大小超过我们包的大小， 我们进行拆包发送处理
    for (int i = 0; i < FILE_SIZE; i += PACK_SIZE)
    {
        MSG_HEAD msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_ID = MSG_READY;
        printf("i = %d\n", i);
        msg.un.Packet.pack_No = i;
        // 最后一个包
        if (i + PACK_SIZE + 1 > FILE_SIZE)
        {
            msg.un.Packet.n_size = FILE_SIZE - i; // 最后一个包的大小
        }
        else
        {
            msg.un.Packet.n_size = PACK_SIZE;
        }

        // memcpy(msg.packet.buf, g_filebuf+ msg.packet.nStart, msg.packet.nsize);

        // 		//printf("文件大小：%d 文件内容:%s", g_filesize,msg.packet.buf);
        // 		if (SOCKET_ERROR == send(clifd, (char *)&msg,sizeof(struct MsgHeader), 0)){
        // 			printf("文件发送失败:%d\n",WSAGetLastError());
        // 		}

        memcpy(msg.un.Packet.file_buf, file_buf + msg.un.Packet.pack_No, msg.un.Packet.n_size);

        // strncpy(msg.un.Packet.file_buf, file_buf, PACK_SIZE - 1);
        // msg.un.Packet.n_size = FILE_SIZE;
        int ret = send(clientfd, (char *)&msg, sizeof(msg), 0);

        if (ret <= 0)
        {
            printf("send 发送失败\n");
            return false;
        }
        printf("aaa\n");
    }

    return true;
}

bool success_to_client(int clientfd)
{
    MSG_HEAD msg;
    memset(&msg, 0, sizeof(msg));
    msg.msg_ID = MSG_SUCCESSED;
    int ret = send(clientfd, (char *)&msg, sizeof(msg), 0);
    if (ret <= 0)
    {
        printf("send() error\n");
        return false;
    }
    return true;
}

// bool send_Dir_name(int clientfd)
// {
//     Work_Dir d;
//     memset(&d, 0, sizeof(d));
//     getcwd(d.dir_name, 255);

//     // 将结果发送给客户端
//     int ret = send(clientfd, (char *)&d, sizeof(d), 0);
//     if(ret <= 0)
//     {
//         printf("服务器地址发送失败\n");
//         return false;
//     }
//     return true;
// }

bool get_cmd(int cliendfd)
{
    char cmd_buf[256];
    memset(&cmd_buf, 0, sizeof(cmd_buf));
    int ret = recv(cliendfd, (char *)cmd_buf, sizeof(cmd_buf), 0);
    if (ret <= 0)
    {
        printf("服务器 命令接收失败\n");
        // exit(-1);
        return false;
    }

    if (strcmp(cmd_buf, "ls") == 0)
    {
        // ls 命令，列出当前服务器的工作目录下的文件， 将其信息发送给客户端
        DIR *dir = NULL;
        char strpwd[301];
        memset(strpwd,0,sizeof(strpwd));
        getcwd(strpwd,300);
        if ((dir = opendir(strpwd)) == 0)
        {
            printf("当前目录打开失败\n");
            return false;
        }
        // 用于存放从目录中读取到的文件和目录信息
        // struct dirent *stdinfo;
        while (send_file_msg(cliendfd, dir, strpwd))
        {
            sleep(1);
        }
        char *ss = "finish";
        // 发送结束信息
        send(cliendfd, ss, strlen(ss) + 1, 0);
    }
    else if (strncasecmp(cmd_buf, "cd", 2) == 0)
    {
        // cd 命令
        // 服务器进入到客户端指定的目录并显示这个目录下的文件
        char temp[256] = {0};
        // 将路径保存
        strcpy(temp, cmd_buf + 3);
        DIR *dir = NULL;
        if ((dir = opendir(temp)) == 0)
        {
            printf("目录[%s]打开失败\n", temp);
            return false;
        }

        while(send_file_msg(cliendfd, dir, temp))
        {
            // sleep(1);
            usleep(500000);
            
        }
        char *ss = "finish";
        send(cliendfd, ss, strlen(ss) + 1, 0);
    }
}

bool send_file_msg(int clientfd,DIR *dir, char *path)
{
    struct dirent *stdinfo;
    if ((stdinfo = readdir(dir)) == NULL)
        return false;
    else
    {
        memset(send_buff, 0, sizeof(send_buff));
        char *type = NULL;
        if (stdinfo->d_type == 4)
        {
            type = "目录";
        }
        if (stdinfo->d_type == 8)
        {
            type = "文件";
        }
        sprintf(send_buff, "类型：%s  文件名：%s/%s", type, path,stdinfo->d_name);
        int ret = send(clientfd, (char *)send_buff, strlen(send_buff) + 1, 0);
        if (ret <= 0)
        {
            printf("发送失败....\n");
            return false;
        }
    }
    return true;
}